#include <iostream>
#include <mutex>

using namespace std;

template <class T>
class my_shared_ptr
{
public:
    my_shared_ptr(T *data = nullptr)
        : data_(data), ref_count_(new int(1)), mtx_(new mutex)
    {
    }

    ~my_shared_ptr()
    {
        release();
    }

    my_shared_ptr(const my_shared_ptr<T> &sp)
        : data_(sp.data_), ref_count_(sp.ref_count_), mtx_(sp.mtx_)
    {
        add_ref_count();
    }

    my_shared_ptr<T> &operator=(const my_shared_ptr<T> &sp)
    {
        if (data_ != sp.data_)
        {
            release();
            data_ = sp.data_;
            ref_count_ = sp.ref_count_;
            mtx_ = sp.mtx_;
            add_ref_count();
        }
        return *this;
    }

    T& operator*() { return *data_; }
    T* operator->() { return data_; }

    int use_count() const { return *ref_count_; }

    T* get() { return data_; }

private:
    void add_ref_count()
    {
        mtx_->lock();
        ++(*ref_count_);
        mtx_->unlock();
    }

    void release()
    {
        bool deleteFlag = false;
        mtx_->lock();
        if (--(*ref_count_) == 0)
        {
            delete data_;
            delete ref_count_;
            deleteFlag = true;
        }
        mtx_->unlock();

        if (deleteFlag)
        {
            delete mtx_;
        }
    }

private:
    T *data_;
    int *ref_count_;
    mutex *mtx_;
};

int main() {
    my_shared_ptr<int> sp1(new int(1));
    cout << sp1.use_count() << endl;

    {
        my_shared_ptr<int> sp2(sp1);
        cout << sp2.use_count() << endl;
        *sp2 = 5;
    }

    cout << sp1.use_count() << endl;
    cout << *sp1 << endl;

    return 0;
}